<template>
  <div class="employees-container">
    <div class="app-container">
      <page-tools>
        <template #left>
          <span>总记录数: {{ total }} 条</span>
        </template>
        <template #right>
          <el-button
            type="warning"
            size="small"
            @click="$router.push('/employees/import')"
          >excel导入</el-button>
          <el-button
            v-allow="'export_excel'"
            type="danger"
            size="small"
            @click="hExport"
          >excel导出</el-button>
          <el-button
            type="primary"
            size="small"
            @click="showDialog = true"
          >新增员工</el-button>
        </template>
      </page-tools>

      <el-card style="margin-top: 10px">
        <el-table :data="employees" border>
          <el-table-column label="序号" type="index" />
          <el-table-column label="姓名" prop="username" />
          <el-table-column label="头像" width="80">
            <template v-slot="{ row }">
              <!-- <img :src="row.staffPhoto"> -->
              <ImageHolder :src="row.staffPhoto" />
            </template>
          </el-table-column>
          <el-table-column sortable label="工号" prop="workNumber" />
          <el-table-column label="聘用形式">
            <template v-slot="{ row }">
              {{ formatEmployement(row.formOfEmployment) }}
            </template>
          </el-table-column>
          <el-table-column label="部门" prop="departmentName" />
          <el-table-column sortable label="入职时间" prop="timeOfEntry" />
          <el-table-column label="操作" width="280">
            <template v-slot="{ row }">
              <el-button
                type="text"
                size="small"
                @click="$router.push('/employees/detail/' + row.id)"
              >查看</el-button>
              <el-button
                type="text"
                size="small"
                @click="hAssignRole(row.id)"
              >分配角色</el-button>
              <el-button
                v-allow="'delete_employee'"
                type="text"
                size="small"
                @click="hDel(row.id)"
              >删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页组件 -->
        <el-row
          type="flex"
          justify="center"
          align="middle"
          style="height: 60px"
        >
          <!-- 分页组件 -->
          <!-- current-page: 当前页 -->
          <!-- page-size: 每页显示多少条 -->
          <!-- total: 总条数 -->
          <!-- page-sizes: 设置每页显示多少条的选项 -->
          <!-- size-change: 当 page-size 发生变化时触发 -->
          <!-- current-change: 当前页发生变化时触发 -->
          <el-pagination
            :current-page="pageParams.page"
            :page-sizes="[10, 15, 20]"
            :page-size="pageParams.size"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            @size-change="hSizeChange"
            @current-change="hCurrentChange"
          />
        </el-row>
      </el-card>
    </div>
    <!-- 添加或编辑的弹框 -->
    <el-dialog
      title="添加或编辑"
      :visible.sync="showDialog"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      @closed="$refs.addOrEdit.resetForm()"
    >
      <!-- v-if="showDialog": 当 dialog 打开时创建子组件, dialog 关闭时销毁子组件 -->
      <AddOrEdit ref="addOrEdit" @success="hSuccess" @close="hClose" />
    </el-dialog>
    <el-dialog
      title="分配角色"
      :visible.sync="showDialogRole"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <!-- v-if 可以解决问题, 但是我们要学新知识 -->
      <AssignRole
        ref="assignRole"
        :user-id="userId"
        @close="showDialogRole = false"
      />
    </el-dialog>
  </div>
</template>

<script>
import { getEmployees, delEmployees } from '@/api/employees'
import empConstant from '@/constant/employees'
import AddOrEdit from './empDialog.vue'
import AssignRole from './assignRole.vue'
// console.log('我是47行的代码')
// hireType: [
//     {
//       id: 1,
//       value: '正式'
//     },
//     {
//       id: 2,
//       value: '非正式'
//     }
//   ],
// 将聘用形式的常量转成: { 1: '正式', 2: '非正式' }
// const hireMap = {}
// 小作业(基础比较好的同学可以试试): 将该代码进一步优化, 一行搞定: reduce
// empConstant.hireType.forEach(item => {
//   hireMap[item.id] = item.value
// })
// console.log(hireMap)

// 使用 reduce 高级做法
// 优雅
const hireMap = empConstant.hireType.reduce(
  (hireMap, item) => ({ ...hireMap, [item.id]: item.value }),
  {}
)

// 局部注册 用户体验不好
// 很多地方都需要用到
// import PageTools from '@/components/PageTools'

export default {
  // components: {
  //   PageTools
  // }
  components: {
    AddOrEdit,
    AssignRole
  },
  // 只有 data 中的数据是响应式的
  // 原理: 数据劫持, API: Object.defineProperty() 可以监听到对象的属性改变
  // 也有一些缺陷: arr: [1, 2, 3], arr[0] = 'a' 这样是拦截不到的
  // this.$set()
  // 所以在 Vue 3 之后, 尤大大对整个 Vue 框架的响应式模块进行了重写
  // Vue 3 响应式原理: 数据代理, API: Proxy (代理) ES7 的 API
  data() {
    return {
      pageParams: {
        page: 1,
        size: 10
      },
      total: 0,
      employees: [],
      showDialog: false,
      showDialogRole: false,
      userId: ''
    }
  },

  created() {
    this.loadEmployees()
  },
  methods: {
    async loadEmployees() {
      // 发请求拿数据
      const res = await getEmployees(this.pageParams).catch((e) =>
        console.log('获取员工信息失败:', e)
      )
      // console.log(res.data.rows)
      this.employees = res.data.rows
      this.total = res.data.total
    },
    formatEmployement(code) {
      // console.log(code)

      // 需求: 通过 code 去 constant/employees.js 中的 hireType 找到对应的 value 返回
      // console.log(empConstant.hireType)
      // const result = empConstant.hireType.find(item => item.id === code)
      // console.log(result.value)
      // return empConstant.hireType.find(item => item.id === code).value
      // 问题: 函数会执行 n 次, 循环会执行 m 次, 所以如果不做优化, 代码将执行 n * m 次, 非常损耗性能

      // const hireMap = {
      //   0: '女',
      //   1: '男'
      // }
      // hireMap[code]

      return hireMap[code]
    },
    hSizeChange(val) {
      // console.log('每页显示条数:', val)
      // 修改每页显示的条数
      this.pageParams.size = val
      // 重新发起请求获取最新的数据
      this.loadEmployees()
    },
    hCurrentChange(val) {
      // console.log('当前页:', val)
      // 修改当前页码值
      this.pageParams.page = val
      // 重发请求
      this.loadEmployees()
    },
    async hDel(id) {
      // 提示用户确定删除吗
      const result = await this.$confirm('真的要删除吗?', '提示', {
        type: 'warning'
      })
      // 趁早 return
      if (result !== 'confirm') return

      // 用户点击确定后发请求
      const res = await delEmployees(id).catch((e) =>
        this.$message.error(e.message)
      )

      // 根据结果提醒用户
      this.$message.success(res.message)

      // 处理分页的问题: 最后一页只有一个元素时
      // 所有分页的删除 Bug 都是这么处理
      if (this.employees.length === 1 && this.pageParams.page > 1) {
        this.pageParams.page--
      }

      // 重新获取数据
      this.loadEmployees()
    },
    hClose() {
      // 关闭 dialog
      this.showDialog = false
    },
    hSuccess() {
      // 关闭 dialog
      this.showDialog = false

      // 在本地将 total 自增 1
      this.total++

      // 计算最新的最后一页
      this.pageParams.page = Math.ceil(this.total / this.pageParams.size)

      // 更新数据
      this.loadEmployees()
    },
    async hExport() {
      // import('@/vendor/Export2Excel').then(excel => {
      //   // excel表示导入的模块对象
      //   console.log(excel)
      //   excel.export_json_to_excel({
      //     header: ['姓名', '工资'], // 表头 必填
      //     data: [
      //       ['刘备', 100],
      //       ['关羽', 500]
      //     ], // 具体数据 必填
      //     filename: 'excel-list', // 文件名称
      //     autoWidth: true, // 宽度是否自适应
      //     bookType: 'xlsx' // 生成的文件类型
      //   })
      // })

      // 异步加载 Excel 导出的库
      const excel = await import('@/vendor/Export2Excel')
      // excel表示导入的模块对象
      // console.log(excel)

      // 发请求获取数据
      const res = await getEmployees({ page: 1, size: this.total }).catch(
        (e) => e
      )
      if (!res.success) return console.dir(res)
      // console.log(res.data.rows)

      // 将数据转换成需要的格式
      const { header, data } = this.format2Excel(res.data.rows)

      // 导出 Excel
      excel.export_json_to_excel({
        // header: ['姓名', '工资'], // 表头 必填
        header, // 表头 必填
        // data: [
        //   ['刘备', 100],
        //   ['关羽', 500]
        // ], // 具体数据 必填
        data, // 具体数据 必填
        filename: '员工信息表', // 文件名称
        autoWidth: true, // 宽度是否自适应
        bookType: 'xlsx' // 生成的文件类型
      })
    },
    format2Excel(list) {
      const mapInfo = {
        id: '编号',
        password: '密码',
        mobile: '手机号',
        username: '姓名',
        timeOfEntry: '入职日期',
        formOfEmployment: '聘用形式',
        correctionTime: '转正日期',
        workNumber: '工号',
        departmentName: '部门',
        staffPhoto: '头像地址'
      }
      let header = []
      let data = []
      // 起点
      // [ { username: '管理员', workNumber: '9002' }, { username: '罗晓晓', workNumber: '9003' } ]
      // 终点
      // header: ['姓名', '工号']
      // data: [ ['管理员', '9002'], ['罗晓晓', '9003'] ]

      // 小目标1: header -> 全英文 -> 转成中文
      // 分析: 每个数据项的属性名数量和内容都是一样的, 不需要循环拿所有的数据项
      // 只需要拿到某一个数据, 将其所有的属性名获取到即可
      if (list.length === 0) return { header, data }
      // 取第一项
      // const obj = list[0]
      // Object.keys 获取对象所有属性名  =>  ['id', 'mobile', 'username'...]
      // map: 映射, 循环每一个数据项, 处理后返回
      // mapInfo[k] ==> 通过英文属性名查找对应的中文 => ['编号', '手机号', '姓名'...]
      header = Object.keys(list[0]).map((k) => mapInfo[k]) // k: id / mobile / username
      // console.log(header)

      // 小目标2: data
      // 分析: 通过观察发现, 就是将数组中的每个数据对象, 转到数组中的每个数组 -> 对象转成数组 (只要 value 不要 key)
      // 第一步肯定要循环 (获取每一个数据)
      data = list.map((item) => {
        // item: { username: '管理员', formOfEmployment: 1 ...}
        // return []
        // 交给后台处理, 前端不背这锅
        // if (item.formOfEmployment === undefined) {
        //   item.formOfEmployment = 2
        // }

        // 还需要对聘用形式进行处理
        // hireMap: { 0: '无', 1: '正式', 2: '非正式' }
        const k = item.formOfEmployment // 1
        // console.log('k', k)
        item.formOfEmployment = hireMap[k] // 正式 => 覆盖回去
        // console.log('item', item)
        return Object.values(item) // ['管理员', '9002']
      })
      // console.log(data)
      return { header, data }
    },
    async hAssignRole(id) {
      // 当前点击的用户 id
      console.log('用户 ID:', id)
      this.userId = id

      // 显示 dialog
      this.showDialogRole = true

      // 加一个 nextTick 就好了
      // 原因: props 的更新是异步的
      await this.$nextTick()

      // 调用子组件的方法让它发请求获取数据即可
      this.$refs.assignRole.loadRolesById()
    }
  }
}
</script>
